#ifndef _LOG_H_
#define _LOG_H_
#include <stdio.h>
#include <stdlib.h>

#define USE_LOG_COLOR (0)

#if USE_LOG_COLOR
    #define ESC_START "\033["
    #define ESC_END "\033[0m"
    #define COLOR_FATAL "31;40;5m"
    #define COLOR_ALERT "31;40;1m"
    #define COLOR_CRIT "31;40;1m"
    #define COLOR_ERROR "35;40;1m"
    #define COLOR_WARN "33;40;1m"
    #define COLOR_NOTICE "34;40;1m"
    #define COLOR_INFO "32;40;1m"
    #define COLOR_DEBUG "36;40;1m"
    #define COLOR_TRACE "37;40;1m"
#else
    #define ESC_START
    #define ESC_END
    #define COLOR_FATAL
    #define COLOR_ALERT
    #define COLOR_CRIT 
    #define COLOR_ERROR
    #define COLOR_WARN 
    #define COLOR_NOTICE
    #define COLOR_INFO
    #define COLOR_DEBUG
    #define COLOR_TRACE
#endif

#define LOG_LEVEL_TRACE  (0)
#define LOG_LEVEL_DEBUG  (1)
#define LOG_LEVEL_INFO   (2)
#define LOG_LEVEL_NOTICE (3)
#define LOG_LEVEL_WARN   (4)
#define LOG_LEVEL_ERROR  (5)
#define LOG_LEVEL_CRIT   (6)
#define LOG_LEVEL_ALERT  (7)
#define LOG_LEVEL_FATAL  (8)

#define LOG_LEVEL LOG_LEVEL_DEBUG

#define LOG_FATAL(fmt, args...)                                                              \
    do {                                                                                     \
        if (LOG_LEVEL_FATAL >= LOG_LEVEL)                                                    \
        {                                                                                    \
            fprintf(stderr, ESC_START COLOR_FATAL "F[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                                 \
        }                                                                                    \
    } while (0)

#define LOGF(fmt, ...) LOG_FATAL(fmt, ##__VA_ARGS__)

#define LOG_ERROR(fmt, args...)                                                              \
    do {                                                                                     \
        if (LOG_LEVEL_ERROR >= LOG_LEVEL)                                                    \
        {                                                                                    \
            fprintf(stderr, ESC_START COLOR_ERROR "E[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                                 \
        }                                                                                    \
    } while (0)

#define LOGE(fmt, ...) LOG_ERROR(fmt, ##__VA_ARGS__)

#define LOG_WARN(fmt, args...)                                                     \
    do {                                                                           \
        if (LOG_LEVEL_WARN >= LOG_LEVEL)                                           \
        {                                                                          \
            printf(ESC_START COLOR_WARN "W[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                       \
        }                                                                          \
    } while (0)

#define LOGW(fmt, ...) LOG_WARN(fmt, ##__VA_ARGS__)

#define LOG_NOTICE(fmt, args...)                                                     \
    do {                                                                             \
        if (LOG_LEVEL_NOTICE >= LOG_LEVEL)                                           \
        {                                                                            \
            printf(ESC_START COLOR_NOTICE "N[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                         \
        }                                                                            \
    } while (0)

#define LOGN(fmt, ...) LOG_NOTICE(fmt, ##__VA_ARGS__)

#define LOG_INFO(fmt, args...)                                                     \
    do {                                                                           \
        if (LOG_LEVEL_INFO >= LOG_LEVEL)                                           \
        {                                                                          \
            printf(ESC_START COLOR_INFO "I[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                       \
        }                                                                          \
    } while (0)

#define LOGI(fmt, ...) LOG_INFO(fmt, ##__VA_ARGS__)

#define LOG_DEBUG(fmt, args...)                                                     \
    do {                                                                            \
        if (LOG_LEVEL_DEBUG >= LOG_LEVEL)                                           \
        {                                                                           \
            printf(ESC_START COLOR_DEBUG "D[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                        \
        }                                                                           \
    } while (0)

#define LOGD(fmt, ...) LOG_DEBUG(fmt, ##__VA_ARGS__)

#define LOG_VERBOSE(fmt, args...)                                                   \
    do {                                                                            \
        if (LOG_LEVEL_TRACE >= LOG_LEVEL)                                           \
        {                                                                           \
            printf(ESC_START COLOR_TRACE "V[" __FILE__ ":%d %s] " fmt ESC_END,      \
                __LINE__, __func__, ##args);                                        \
        }                                                                           \
    } while (0)

#define LOGV(fmt, ...) LOG_VERBOSE(fmt, ##__VA_ARGS__)

#endif // _LOG_H_
